# Import the 'os' module to interact with the operating system, for example, to get environment variables.
import os

# Import the base Model class from Flask-AppBuilder, which this model will inherit from.
from flask_appbuilder import Model
# Import column types from SQLAlchemy to define the database schema.
from sqlalchemy import Column, Integer, String

# Import the Flask application instance to access its configuration.
from myapp.app import app
# Import a custom base model that may contain shared logic or properties.
from myapp.models.base import MyappModelBase
# Import a custom audit mixin for tracking creation and modification details.
from myapp.models.helpers import AuditMixinNullable


# Get the metadata object from the base Model class. Metadata stores information about the database schema.
metadata = Model.metadata
# Get the application's configuration object.
conf = app.config


# Define the Codeset class, which maps to the 'codeset' table in the database.
# This model represents an uploaded code package or set.
class Codeset(Model, AuditMixinNullable, MyappModelBase):
    # Specifies the name of the database table for this model.
    __tablename__ = 'codeset'
    
    # Defines the primary key column for the table.
    id = Column(Integer, primary_key=True, comment='id')
    # Defines a column for the name of the codeset.
    name = Column(String(200), nullable=True, comment='代码包名称')
    # Defines a column for the owner of the codeset, likely a username.
    owner = Column(String(200), nullable=True, comment='代码包拥有人')
    # Defines a column for the original name of the uploaded file.
    filename = Column(String(200), nullable=True, default='0', comment='原上传文件名')
    # Defines a column for the status of the codeset (e.g., 'uploading', 'success', 'failed').
    status = Column(String(200), nullable=True, default='uploading', comment='上传状态')
    # Defines a column to store the size of the codeset file (e.g., "10.5 MB").
    storage_size = Column(String(200), nullable=True, default='', comment='存储大小')
    # Defines a column to specify the storage backend type (e.g., 'local', 'minio').
    storage_type = Column(String(200), nullable=True, default='0', comment='存储方式')
    # Defines a column for the path where the codeset is stored.
    codeset_path = Column(String(200), nullable=True, default='0', comment='存储地址')
    # Defines a column for the path where the codeset has been unpacked or extracted.
    unpack_path = Column(String(200), nullable=True, default='0', comment='解压后的地址')
    # Defines a soft-delete flag. A value of 1 (or non-zero) means the record is considered deleted.
    is_deleted = Column(Integer, nullable=False, default=0, comment='是否删除')
    # Defines a column to store the reason for failure if the upload or processing fails.
    fail_log = Column(String(200), nullable=True, comment='失败原因')
    # Defines a column for the deployment region, useful in multi-region environments.
    region = Column(
        String(100), nullable=False, default='default', server_default='default', comment='地区'
    )

    # Defines the official string representation of a Codeset instance.
    def __repr__(self):
        """
        Returns a string representation of the model instance, which is useful for debugging.
        It returns the name of the codeset.
        """
        return self.name

    # This property calculates and returns the path to the original uploaded file.
    @property
    def origin_path(self):
        """
        Constructs the relative storage path for the original uploaded file
        based on the owner's name and the original filename.
        """
        # uid = self.changed_by_fk
        # The owner's name is used to create a user-specific directory.
        name = self.owner
        # If the filename is not set, return an empty string.
        if self.filename is None or self.filename == '':
            return ''
        # Concatenate the owner, a sub-folder 'origin', and the filename to form the path.
        return name + '/origin/' + self.filename

    # This property serves as an alias for the 'owner' attribute.
    @property
    def username(self):
        """
        A convenience property to get the owner's name.
        """
        return self.owner

    # This property checks if the storage backend is MinIO or a similar service.
    @property
    def is_minio_storage(self):
        """
        Determines if the storage type is MinIO-compatible.
        It checks the 'storage_type' field and falls back to an environment
        variable 'STORAGE_MEDIA' if the field is not set.
        """
        # Get the storage type from the instance attribute.
        st_type = self.storage_type
        # If the storage type is not set in the database record, check the environment variable as a fallback.
        if st_type is None or st_type == '':
            st_type = os.getenv('STORAGE_MEDIA')
        # Check if the determined storage type matches known identifiers for MinIO or ARM-based storage.
        return st_type == 'MINIO' or st_type == 'minio' or st_type == 'arm' or st_type == 'ARM'
